package com.xishu.service;

import com.xishu.annotation.oplog.OplogAnnotation;
import com.xishu.entity.AbstractEntity;
import com.xishu.entity.Company;
import com.xishu.entity.oplog.OpLog;
import com.xishu.entity.User;
import com.xishu.entity.oplog.OpName;
import com.xishu.entity.shop.Shop;
import com.xishu.util.ClassUtil;
import com.xishu.util.ServletUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.Transient;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class OpLogService {
    private static OpLogService instance = new OpLogService();
    private static Logger logger = LoggerFactory.getLogger(OpLogService.class);
    private CommonService commonService = CommonService.getInstance();

    private OpLogService() {
    }

    public static OpLogService getInstance() {
        return instance;
    }

    /**
     * 添加删除日志
     *
     * @param baseEntity
     */
    public void createDeleteLog(AbstractEntity baseEntity) {
        try {
            logger.info("delete object is {}", baseEntity);
            User user = ServletUtil.getUser();
            OpLog opLog = new OpLog();

            if (user != null) {
                opLog.setUserId(user.getId());
                opLog.setUserName(user.getName());
            }

            opLog.setIpAddress(ServletUtil.getRequest().getRemoteAddr());
            OpName opName = (OpName) baseEntity;

            String deleteField = opName.getOpName();

            opLog.setOpType(opName.opType());
            opLog.setTargetId(baseEntity.getId());
            opLog.setTargetName(opName.getOpName());
            opLog.setFieldName(deleteField);
            opLog.addRequestId(ServletUtil.getRequestId());

            writeShopAndCompanyInfo(baseEntity, opLog);
            commonService.createObject(opLog);
        } catch (Exception e) {
            logger.error("e", e);
        }

    }


    /**
     * 写操作日志，在创建对象的时候
     *
     * @param baseEntity
     */
    public void createLog_createObject(AbstractEntity baseEntity) {
        try {
            if (!(baseEntity instanceof OpName)) {
                logger.info("no need log record");
                return;
            }

            User user = ServletUtil.getUser();

            if (user == null) {
                logger.info("user is empty");
                return;
            }

            OpName opName = (OpName) baseEntity;

            String[] fieldNameList = opName.fieldName();
            List<String> fieldValueList = Arrays.stream(fieldNameList).map(f -> {
                Field field = ClassUtil.getInstance().getField(baseEntity.getClass(), f);
                try {
                    return field.get(baseEntity).toString();
                } catch (IllegalAccessException e) {
                    logger.error("e", e);
                    return "";
                }
            }).collect(Collectors.toList());

            OpLog opLog = new OpLog();

            if (user != null) {
                opLog.setUserId(user.getId());
                opLog.setUserName(user.getName());
            }

            opLog.setIpAddress(ServletUtil.getRequest().getRemoteAddr());
            opLog.setFieldName(String.join(":", fieldValueList.toArray(new String[fieldValueList.size()])));
            opLog.setFieldValue("创建");

            opLog.setOpType(opName.opType());
            opLog.setTargetId(baseEntity.getId());
            opLog.setTargetName(opName.getOpName());
            opLog.addRequestId(ServletUtil.getRequestId());
            writeShopAndCompanyInfo(baseEntity, opLog);
            commonService.createObject(opLog);
        } catch (Exception e) {
            logger.error("e", e);
        }
    }

    /**
     * 写操作日志，在更新对象的时候
     *
     * @param baseEntity
     */
    public void createLog(AbstractEntity baseEntity) {
        try {
            User user = ServletUtil.getUser();

            Arrays.stream(baseEntity.getClass().getDeclaredFields()).filter(f -> {
                //过滤不是ID，也不空的字段
                try {
                    f.setAccessible(true);
                    Transient aTransient = f.getAnnotation(Transient.class);
                    return !"id".equals(f.getName()) && f.get(baseEntity) != null && f.getAnnotation(OplogAnnotation.class) != null && aTransient == null;
                } catch (IllegalAccessException e) {
                    logger.error("e", e);
                    return false;
                }
            }).forEach(f -> {
                OplogAnnotation oplogAnnotation = f.getAnnotation(OplogAnnotation.class);
                OpLog opLog = new OpLog();


                if (user != null) {
                    opLog.setUserId(user.getId());
                    opLog.setUserName(user.getName());
                }

                opLog.setIpAddress(ServletUtil.getRequest().getRemoteAddr());
                opLog.setFieldName(oplogAnnotation.fieldName());

                try {
                    opLog.setFieldValue(f.get(baseEntity).toString());
                } catch (IllegalAccessException e) {
                    logger.error("e", e);
                }

                OpName opName = (OpName) baseEntity;
                opLog.setOpType(opName.opType());
                opLog.setTargetId(baseEntity.getId());
                opLog.setTargetName(opName.getOpName());
                opLog.addRequestId(ServletUtil.getRequestId());


                writeShopAndCompanyInfo(baseEntity, opLog);

                try {
                    commonService.createObject(opLog);
                } catch (Exception e) {
                    logger.error("e", e);
                }
            });
        } catch (Exception e) {
            logger.error("e", e);
        }
    }

    private void writeShopAndCompanyInfo(AbstractEntity baseEntity, OpLog opLog) {
        Field shopIdField = ClassUtil.getInstance().getField(baseEntity.getClass(), "shopId");
        Field companyIdField = ClassUtil.getInstance().getField(baseEntity.getClass(), "companyId");

        //如果有包含shopId，那么要写shopId,也写companyId
        if (shopIdField != null) {
            logger.info("will write shop id field");
            Long entityId = baseEntity.getId();

            try {
                AbstractEntity entityInDb = commonService.findEntity(entityId, baseEntity.getClass());
                Object shopId = shopIdField.get(entityInDb);
                if (shopId != null) {
                    Shop shop = commonService.findEntity(Long.valueOf(shopId.toString()), Shop.class);
                    opLog.setShopId(shop.getId());
                    opLog.setCompanyId(shop.getCompanyId());
                }
            } catch (Exception e) {
                logger.error("e", e);
            }
        }

        if (companyIdField != null) {
            logger.info("will write company id field");
            //如果没有shopId,但是有companyId，那么写companyId
            Long entityId = baseEntity.getId();

            try {
                AbstractEntity entityInDb = commonService.findEntity(entityId, baseEntity.getClass());
                Object companyId = companyIdField.get(entityInDb);
                if (companyId != null) {
                    opLog.setCompanyId(Long.valueOf(companyId.toString()));
                }
            } catch (Exception e) {
                logger.error("e", e);
            }
        }
    }

}
